package com.tt.fashionWebSite.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.AlgorithmParameters;
import java.security.MessageDigest;
import java.security.spec.KeySpec;

/**
 * **********************************************************************
 * <p/>
 * iServiceSoft Inc \u00a9 - 2009 All Rights Reserved
 * _____________________________________________
 * <p/>
 * NOTICE:  All information contained herein is, and remains
 * the property of iServiceSoft. Intellectual and technical concepts
 * contained herein are proprietary of iServiceSoft and may be covered
 * by U.S. and Foreign Patents, patents in process, and are protected
 * by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from iServiceSoft Incorporated.
 * <p/>
 * ***********************************************************************
 */
@SuppressWarnings("restriction")
public class CryptographyDataUtils {

   private static BASE64Decoder decoder;
   private static BASE64Encoder encoder;
   private static MessageDigest digest;
   private static Cipher cipher;
   private static final String SALT = "iDentalL";
   private static String secret = "1fsRjdvKsiE8OQ53";
   private static SecretKey secretKey;
   private static final int IV_LENGTH = 24;
   private final static Logger logger = LoggerFactory.getLogger(CryptographyDataUtils.class);

   static {
      try {
         decoder = new BASE64Decoder();
         encoder = new BASE64Encoder();
         digest = MessageDigest.getInstance("SHA-256");

         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
         KeySpec keySpec = new PBEKeySpec(secret.toCharArray(),SALT.getBytes(), 65536, 256);
         SecretKey tmp = keyFactory.generateSecret(keySpec);
         secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
         cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

      } catch (Exception e) {
         StringWriter sw = new StringWriter();
         e.printStackTrace(new PrintWriter(sw));
         logger.error("Init Cryptography error: " + sw.toString());
      }
   }

   public static String encryptWithSHA(String encryptData) {
      return encoder.encode(digest.digest(encryptData.getBytes()));
   }

   public static String encryptWithAES(String encryptData) {
      try {
         cipher.init(Cipher.ENCRYPT_MODE, secretKey);
         AlgorithmParameters algorithmParameters = cipher.getParameters();
         byte[] iv = algorithmParameters.getParameterSpec(IvParameterSpec.class).getIV();
         return  encoder.encode(iv) + encoder.encode(cipher.doFinal(encryptData.getBytes()));
      }catch (Exception e) {
         StringWriter sw = new StringWriter();
         e.printStackTrace(new PrintWriter(sw));
         logger.error("Encrypt Data wrong: " + encryptData);
         logger.error("Encrypt with AES is failed: " + sw.toString());
         return encryptData;
      }
   }

   public static String decryptWithAES(String encryptData) {
      try {
         if (encryptData == null || "".equals(encryptData.trim())){
            return "";
         }

         byte[] iv = decoder.decodeBuffer(encryptData.substring(0,IV_LENGTH));
         byte[] encrypted = decoder.decodeBuffer(encryptData.substring(IV_LENGTH));
         cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
         byte[] decrypted = cipher.doFinal(encrypted);
         return new String(decrypted);
      }catch (Exception ex) {
         StringWriter sw = new StringWriter();
         ex.printStackTrace(new PrintWriter(sw));
         logger.error("Decrypt Data wrong: " + encryptData);
         logger.error("Decrypt with AES is failed: "  + sw.toString());
         return encryptData;
      }
   }

   public static String encryptWithAES(String encryptData, boolean escape) {
      String encryptedData = encryptWithAES(encryptData);
      if (escape) {
         encryptedData = encryptedData.replaceAll("/", "_");
         encryptedData = encryptedData.replaceAll("\\+", "-");
         encryptedData = encryptedData.replaceAll("=", "*");
      }

      return encryptedData;
   }


   public static String decryptWithAES(String encryptData, boolean escape) {
      if (encryptData == null || "".equals(encryptData.trim())) {
         return "";
      }

      String originalEncryptedData = encryptData;
      if (escape) {
         originalEncryptedData = originalEncryptedData.replaceAll("_", "/");
         originalEncryptedData = originalEncryptedData.replaceAll("\\-", "\\+");
         originalEncryptedData = originalEncryptedData.replaceAll("\\*", "=");
      }

      return decryptWithAES(originalEncryptedData);
   }
}
